﻿using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Workflow;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client.Taxonomy;
using System.Net;

namespace Office365.SharePointOnline.Cmdlets
{
    [System.Management.Automation.Cmdlet(System.Management.Automation.VerbsCommon.Set, "TaxonomyFieldAssociation")]
    public class Set_TaxonomyFieldAssociation : System.Management.Automation.PSCmdlet
    {
        [System.Management.Automation.Parameter(Position = 0, Mandatory = true)]
        public string Url;

        [System.Management.Automation.Parameter(Position = 1, Mandatory = true)]
        public string User;

        [System.Management.Automation.Parameter(Position = 2, Mandatory = true)]
        public string Password;

        // example: Document
        [System.Management.Automation.Parameter(Position = 3, Mandatory = true)]
        public string ContentTypeName;

        // example: YourtermstoreName
        [System.Management.Automation.Parameter(Position = 4, Mandatory = true)]
        public string TermstoreName;

        // example: "Your Termset Name"
        [System.Management.Automation.Parameter(Position = 5, Mandatory = true)]
        public string TermsetName;

        // The sitecolumn that needs to be bound to the anchor in the termset. Example: MySiteColumn
        [System.Management.Automation.Parameter(Position = 6, Mandatory = true)]
        public string SitecolumnName;

        // The specific term to which the sitecolumn needs to be bound. Example: MyTerm
        [System.Management.Automation.Parameter(Position = 7, Mandatory = false)]
        public string AnchorName;

        // use enum instead?
        [System.Management.Automation.Parameter(Position = 8, Mandatory = false)]
        public string AuthenticationMethod;

        // use only if onpremise authentication
        [System.Management.Automation.Parameter(Position = 9, Mandatory = false)]
        public string Domain;

        protected override void ProcessRecord()
        {
            this.WriteVerbose("Starting TaxonomyField Association with contenttype");
            this.WriteVerbose("Logging on to SharePoint Online");
            
            ClientContext context = new ClientContext(Url);
            Web web = context.Web;
            ICredentials credentials;

            // check parameters
            if (string.IsNullOrEmpty(Url))
            {
                this.WriteObject("Error: url is not set");
            }
            else
            {
                if (!string.IsNullOrEmpty(Password) && !string.IsNullOrEmpty(User))
                {
                    AuthenticationHelper authenticationHelper = new AuthenticationHelper() { AuthenticationMethod = AuthenticationMethod, Domain = Domain, Password = Password, User = User };
                    credentials = authenticationHelper.GetCredentials();
                    if (credentials != null)
                    {
                        context.Credentials = credentials as ICredentials;
                    }
                    else
                    {
                        throw new NullReferenceException("No credentials returned.");
                    }
                }
                else
                {
                    this.WriteVerbose("Reusing existing credentials");
                }
                SetTaxonomyFieldAssociation(context, web);
            }          
        }

        private void SetTaxonomyFieldAssociation(ClientContext context, Web web)
        {
            // We want to retrieve the web's properties.
            context.Load(web);
            context.ExecuteQuery();

            this.WriteVerbose(string.Format("Getting contenttype {0}", ContentTypeName));
            var ct = web.ContentTypes;
            context.Load(ct);
            context.ExecuteQuery();
            var ctDocument = ct.Where(c => c.Name == ContentTypeName).FirstOrDefault();
            var fields = ctDocument.Fields;
            context.Load(fields);
            context.ExecuteQuery();

            // Get the taxonomy session
            this.WriteVerbose("Getting taxonomy session.");
            TaxonomySession tx = Microsoft.SharePoint.Client.Taxonomy.TaxonomySession.GetTaxonomySession(context);
            context.Load(tx);
            context.ExecuteQuery();
            var termstores = tx.TermStores;
            context.Load(termstores);
            context.ExecuteQuery();

            // Just selecting the first termstore since there is only one in SharePointOnline
            this.WriteVerbose(string.Format("Getting termstore {0} and termset {1}.", TermstoreName, TermsetName));
            var termStore = termstores[0];
            var groups = termStore.Groups;
            context.Load(groups);
            context.ExecuteQuery();
            var group = groups.Where(g => g.Name == TermstoreName).FirstOrDefault();
            var termSets = group.TermSets;
            context.Load(termSets);
            context.ExecuteQuery();
            var termSet = termSets.Where(s => s.Name == TermsetName).FirstOrDefault();

            // get the anchor (if needed)
            Term anchor = null;
            if (!string.IsNullOrEmpty(AnchorName))
            {
                this.WriteVerbose(string.Format("Getting termset to find anchor {0}", AnchorName));
                var terms = termSet.Terms;
                context.Load(terms);
                context.ExecuteQuery();
                anchor = terms.Where(t => t.Name == AnchorName).FirstOrDefault();
            }

            // getting sitecolumn to associate the termset with
            this.WriteVerbose(string.Format("Getting sitecolumn {0}.", SitecolumnName));
            var sc = web.Fields;
            context.Load(sc);
            context.ExecuteQuery();
            TaxonomyField txField = sc.Where(f => f.InternalName == SitecolumnName).FirstOrDefault() as TaxonomyField; // use internal fieldname
            context.Load(txField);
            context.ExecuteQuery();

            // associate taxonomyfield (sitecolumn) with the termset anchor
            this.WriteVerbose("Associating field with taxonomy field");
            txField.SspId = termStore.Id;
            txField.TermSetId = termSet.Id;
            txField.TargetTemplate = string.Empty;
            if (anchor == null)
            {
                txField.AnchorId = Guid.Empty;
            }
            else
            {
                txField.AnchorId = anchor.Id;
            }
            txField.Update();
            context.ExecuteQuery();

            // associate the sitecolumn with the contenttype
            this.WriteVerbose("Updating contenttype with new updated taxonomyfield");
            FieldLinkCreationInformation fc = new FieldLinkCreationInformation();
            fc.Field = txField;
            ctDocument.FieldLinks.Add(fc);
            ctDocument.Update(false);
            context.ExecuteQuery();
        }
    }
}
